﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace GISCore.Geometry
{
    [Serializable]
    public class Polygon
    {
        public int layer; // the layer in which this polygon belongs to
        public List<Line> lines { set; get; }
        public double x1, x2, y1, y2; //Mininum Bounding Rectagle
        public List<Hole> holes = new List<Hole>();
       
        public Polygon(int layer, List<Line> lines)
        {
            this.lines = lines;
            this.layer = layer;

            if (lines != null)
            {
                foreach (var line in lines)
                {
                    line.polygon = this;
                }
            }
        }

        public override string ToString()
        {
            string str="";
            str=str+lines[0].Start.ToString()+";";
            Line temp = lines[0].next;
            while (temp != lines[0])
            {
                str=str+temp.Start.ToString()+";";
                temp = temp.next;
            }
            return str;
        }

        public void addHole(Hole h)
        {
            holes.Add(h);
        }
        public List<Point> getPoints()
        {
            List<Line> lines = getLines();
            List<Point> points = new List<Point>();
            foreach (Line l in lines)
            {
                List<Point> p = l.getPoints();
                for (int i = 0; i < p.Count-1; i++)
                {
                    points.Add(p[i]);
                }
            }
            
            return points;

        }
        public List<Point> getPoints(bool repeatted)
        {
            List<Line> lines = getLines();
            List<Point> points = new List<Point>();
            foreach (Line l in lines)
            {
                List<Point> p = l.getPoints();
                for (int i = 0; i < p.Count - 1; i++)
                {
                    points.Add(p[i]);
                }
            }
            if (repeatted)
            {
                points.Add(points[0]);
            }
            return points;

        }
        public bool withinPolygon(Point startPoint, Point endPoint)
        {
            return (!enterPolygon(startPoint, endPoint, null));
        }
        public bool enterPolygon(Point targetPoint, Point nextPoint,Line otherLine)
        {
            Line detectLine = new Line(targetPoint, nextPoint,true);
            double x1 =0.0;
            if (targetPoint.getX() > nextPoint.getX())
            {
                x1 =Constants.negativeInfinite;
            }
            else if (targetPoint.getX() < nextPoint.getX())
            {
                x1 = Constants.infinite;
            }
            double y1 = 0.0;
            if (detectLine.getBCoefficient() == 0)
            {
                y1 = targetPoint.getY();
            }
            else {
            y1 = (detectLine.getACoefficient()*x1 + detectLine.getCCoefficient()) / (-1 * detectLine.getBCoefficient());
            }
            if(targetPoint.getX() ==nextPoint.getX()){
                  x1=targetPoint.getX();
                if(targetPoint.getY() > nextPoint.getY()){
                    y1 = Constants.negativeInfinite;
                }
                else{
                    y1 = Constants.infinite;
                }
            }
            Point p1 = new Point(x1, y1);
            detectLine.End=p1;
            List<Line> lines = this.getLines();
            IntersectPoint result = null;
            foreach (Line l in lines)
            {
                if (l == otherLine) continue;
                Intersection i = l.getIntersect(detectLine,out result);
                if (i == Intersection.True)
                {
                    if ((result.getX() != detectLine.Start.getX()) || (result.getY() != detectLine.Start.getY()))
                    {
                        return false;
                    }
  
                }

            }
            return true;
        }

        //This methods return all segments in the polygon. If a segment is intersected, we think there are two segments
        public List<Line> getLines()
        {
            List<Line> newLines = new List<Line>(); ;
            List<Line> childrenLine;
            foreach (Line l in lines)
            {
                if (l.children== null)
                {
                    newLines.Add(l);
                }
                else
                {
                    childrenLine = l.children;
                    foreach (Line ll in childrenLine)
                    {
                        newLines.Add(ll);
                    }
                }
            }
            return newLines;
        }
    }
}
